﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Head : MonoBehaviour
{
    public float rot_up_speed, rot_down_speed, rot_default_speed;
    
    public float resistance_speed, resistance_force;
    public float rotateAngularSpeed = 0.5f;
    public float max_speed = 10f;

    public List<Item> followers;
    public int item_selected, item_count, item_max;

    public enum State { Light, Normal, Heavy };

    // public float[] power;
    // public float power_recovery;
    public Color[] state_color;
    public Dictionary<State, string> stateParamDict = new Dictionary<State, string>()
    {
        { State.Normal, "IsNormal" },
        { State.Heavy, "IsHeavy" },
        { State.Light, "IsLight" }
    };
    public State _state;
    public State state
    {
        get
        {
            return _state;
        }
        set
        {
            string paramName = stateParamDict[value];
            string origParam = stateParamDict[_state];
            _state = value;
            GetComponentInChildren<Animator>().SetBool(origParam, false);
            GetComponentInChildren<Animator>().SetBool(paramName, true);
        }
    }

    public bool onRail = false;

    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("HW!");
        followers = new List<Item>();
        followers.Add(GetComponent<Item>());
        item_selected = 0;
        item_count = 0;
        // power = new float[3];
        state_color = new Color[3];
        state_color[0] = new Color(1, .5f, .5f);
        state_color[1] = new Color(1, 1, 1);
        state_color[2] = new Color(.5f, .5f, 1);
        state = State.Normal;
        // for (int i = 0; i < 3; i++) this.power[i] = 100;
        Cursor.SetCursor(Resources.Load<Texture2D>("Mouse/鼠标"), Vector2.zero, CursorMode.Auto);
        
    }


    // Update is called once per frame
    void Update()
    {
        float scroll = Input.GetAxis("Mouse ScrollWheel");
        int scroll_discrete = (int)(scroll * 10);
        if (scroll_discrete != 0)
        {
            IterateItem();
            // var tar_state = (State)((((int)state + scroll_discrete) % 3 + 3) % 3);
            // SwitchState(tar_state);
        }
        /*
        for (int i = 0; i < 3; i++)
        {
            this.power[i] += power_recovery;
            if (this.power[i] > 100) this.power[i] = 100;
        }
        */
    }

    private Vector2 mouseDownPos;
    private ForceParam.InputType HandleMouse()
    {
        var down = Input.GetMouseButtonDown(0);
        var hold = Input.GetMouseButton(0);
        var up = Input.GetMouseButtonUp(0);
        var pos = (Vector2)Input.mousePosition;
        if (down)
        {
            mouseDownPos = pos;
            Cursor.SetCursor(Resources.Load<Texture2D>("Mouse/抓手"), Vector2.zero, CursorMode.Auto);
        }
        if (hold)
        {
            var dir = pos - mouseDownPos;
            if (dir == Vector2.zero) return ForceParam.InputType.None;
            var upd = Vector2.Dot(dir, Vector2.up);
            var rightd = Vector2.Dot(dir, Vector2.right);
            if (upd > 0 && upd >= Mathf.Abs(rightd)) return ForceParam.InputType.Up;
            if (upd < 0 && -upd >= Mathf.Abs(rightd)) return ForceParam.InputType.Down;
            if (rightd > 0 && rightd >= Mathf.Abs(upd)) return ForceParam.InputType.Right;
            if (rightd < 0 && -rightd >= Mathf.Abs(upd)) return ForceParam.InputType.Left;
        }
        if (up)
            Cursor.SetCursor(Resources.Load<Texture2D>("Mouse/鼠标"), Vector2.zero, CursorMode.Auto);

        return ForceParam.InputType.None;
    }

    private void FixedUpdate()
    {
        Rigidbody2D rigidb = (Rigidbody2D)GetComponent<Rigidbody2D>();

        if (!onRail)
        {
            //float h = Input.GetAxis("Horizontal");
            //float v = Input.GetAxis("Vertical");
            /*
            if (h > 0.9f) rigidb.AddForce(new Vector2(force_scale_right, 0));
            else if (h < -0.9f) rigidb.AddForce(new Vector2(-force_scale_left, 0));
            else if (v > 0.9f) rigidb.AddForce(new Vector2(0, force_scale_up));
            else if (v < -0.9f) rigidb.AddForce(new Vector2(0, -force_scale_down));
            else rigidb.AddForce(new Vector2(0, -force_default));
            
            ForceParam.InputType inputType = ForceParam.InputType.None;
            if (h > 0.9f) inputType = ForceParam.InputType.Right;
            else if (h < -0.9f) inputType = ForceParam.InputType.Left;
            else if (v > 0.9f) inputType = ForceParam.InputType.Up;
            else if (v < -0.9f) inputType = ForceParam.InputType.Down;
            */
            ForceParam.InputType inputType = HandleMouse();
            // check if the power is valid
            if (GetComponent<HeadSkill>().QuerySkill(inputType) == false)
                inputType = ForceParam.InputType.None;

            rigidb.AddForce(ParameterManager.GetInputForce(this, inputType));
            if (rigidb.velocity.magnitude < max_speed)
                rigidb.AddRelativeForce(ParameterManager.GetForwardForce(this));

            if (rigidb.velocity.magnitude > resistance_speed)
                rigidb.AddForce(-rigidb.velocity.normalized * resistance_force);

            float decr = Mathf.Cos(Mathf.Abs(rigidb.rotation) / 60f * 3.14f / 2f);
            //rigidb.angularVelocity = rotateAngularSpeed * v / Time.deltaTime * decr;
            //rigidb.AddTorque(-0.1f * rigidb.rotation);
            if (inputType == ForceParam.InputType.Up)
                rigidb.AddForceAtPosition(new Vector2(0, rot_up_speed) * decr, (Vector2)this.transform.position + new Vector2(10, 0));
            else if (inputType == ForceParam.InputType.Down)
                rigidb.AddForceAtPosition(new Vector2(0, -rot_down_speed) * decr, (Vector2)this.transform.position + new Vector2(10, 0));
            else
                rigidb.AddForceAtPosition(new Vector2(0, rot_default_speed * 0f) * decr, (Vector2)this.transform.position + new Vector2(10, 0));
            float new_angular = rigidb.rotation;
            if (new_angular > 50) rigidb.angularVelocity = rigidb.angularVelocity > 0 ? 0 : rigidb.angularVelocity;
            if (new_angular < -50) rigidb.angularVelocity = rigidb.angularVelocity < 0 ? 0 : rigidb.angularVelocity;
            if (new_angular > 60) rigidb.rotation = 60;
            if (new_angular < -60) rigidb.rotation = -60;
        }
        else
            OnRailBehaviour();
        

    }
    void OnRailBehaviour()
    {
        var center = GetComponentInChildren<HeadCenter>();
        var railCenterPos = center.curRail.transform.position;
        var railDir = center.curRail.transform.TransformDirection(new Vector3(1, 0, 0));

        var rigidb = GetComponent<Rigidbody2D>();

        var targetRot = Vector2.SignedAngle(Vector2.right, railDir);
        rigidb.MoveRotation(targetRot);

        //var Vvert = Vector2.Dot(Vector2.Perpendicular(railDir), rigidb.velocity);
        var Xvert = Vector2.Dot(Vector2.Perpendicular(railDir), center.curRail.transform.position - rigidb.transform.position);

        //if (Xvert / (Vvert * Time.fixedDeltaTime) > 1)
        //{
            transform.position = transform.position + (Vector3)(Xvert * Vector2.Perpendicular(railDir));
        //    return;
        //}

        rigidb.velocity = railDir.normalized * rigidb.velocity.magnitude;

    }

    public void IterateItem()
    {
        var init_item_id = item_selected;
        do
        {
            item_selected++;
            if (item_selected >= followers.Count) item_selected = 0;
        } while (!followers[item_selected].CanWork && item_selected != init_item_id);
        if (followers[item_selected].CanWork)
        {
            SwitchState(followers[init_item_id], followers[item_selected]);
        } else
        {
            Debug.Log("Worker not found");
        }
    }

    private void SwitchState(Item oldItem, Item newItem)
    {
        State state = Item.ItemStateDict[newItem.type];
        oldItem.EndWorking();
        newItem.StartWorking();
        this.state = state;
        this.GetComponent<SpriteRenderer>().color = state_color[(int)state];
    }

    public void EndWorkingItem()
    {
        Debug.Log("Power out, switch to NORMAL");
        SwitchState(followers[item_selected], followers[0]);
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        var obj = collision.collider.gameObject;
        Debug.Log(obj);
        if (obj.layer == LayerMask.NameToLayer("Trap"))
        {
            if (this.state == State.Heavy)
            {
                /*
                obj.layer = LayerMask.NameToLayer("Door");
                //obj.GetComponents<BoxCollider2D>()[0].isTrigger = True;
                obj.GetComponents<Rigidbody2D>()[0].bodyType = RigidbodyType2D.Dynamic;
                obj.GetComponents<Rigidbody2D>()[0].mass = 0.2f;

                var v = GetComponents<Rigidbody2D>()[0].velocity;
                var pos = collision.transform.position;
                Debug.Log(pos);
                Debug.Log(v);
                v = collision.relativeVelocity;
                GetComponents<Rigidbody2D>()[0].velocity = -v*0.8f;
                obj.GetComponents<Rigidbody2D>()[0].AddForceAtPosition(-v * .8f, pos, ForceMode2D.Impulse);
                */
                    
                Destroy(obj);
            }
        }
    }

    private void OnTriggerItem(Collider2D collision)
    {
        var obj = collision.gameObject;
        var item = obj.GetComponent<Item>();
        Debug.Log(item.type);

        if (item.Following) return;
        // Item is collected

        if (followers.Count >= item_max + 1)
        {
            Destroy(obj);
        } else
        {
            item.SetFollowTarget(this, followers[followers.Count - 1].gameObject);
            followers.Add(item);
        }

        /*
        if (this.item_count >= item_max)
            Destroy(obj);
        else
        {
            this.item_count++;

            item[0].follow = true;
            if (followers.Count > 0)
                item[0].follow_target = followers[followers.Count - 1];
            else
                item[0].follow_target = this.gameObject;
            followers.Add(obj);
        }
        */
    }

    private void OntriggerDeathTrap(Collider2D collision) { }
    private void OntriggerPortal(Collider2D collision) { }
    private void OntriggerDoor(Collider2D collision) { }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log(collision.gameObject);
        // Debug.Log(collision.gameObject.layer);
        if (collision.gameObject.layer == LayerMask.NameToLayer("Item"))
            OnTriggerItem(collision);
         


        if (collision.gameObject.layer == LayerMask.NameToLayer("Trap"))
        {
            var obj = collision.gameObject;
            var trap = obj.GetComponents<Trap>();
            Debug.Log(trap[0].type);

            if (trap[0].type == Trap.TrapType.Death) {

                var gc = GameObject.Find("GameController").GetComponent<GameController>();
                gc.EndGame();
            }
            if (trap[0].type == Trap.TrapType.Portal) {
                Vector2 offset = ((Portal)trap[0]).PortalTarget.transform.position - trap[0].transform.position;
                transform.position = transform.position + new Vector3(offset.x, offset.y, 0);
            }
            if (trap[0].type == Trap.TrapType.ForceField)
            {
                var ffparam = ((ForceField)trap[0]).stateParamDict[this.state];
                var angle = ffparam.fieldAngle;
                var magnitude = ffparam.fieldMagnitude;
                var effector = obj.GetComponent<AreaEffector2D>();
                // effector.forceAngle = angle;
                effector.forceMagnitude = magnitude;
            }
        }
        
    }


}
